package xyz.xtt.pay.service.impl;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;

import cn.hutool.core.util.IdUtil;
import jakarta.validation.Valid;
import xyz.xtt.pay.api.enums.PayOrderBusinessTypeEnum;
import xyz.xtt.pay.api.enums.PayOrderStatusEnum;
import xyz.xtt.pay.client.request.FetchUnPaidOrdersRequest;
import xyz.xtt.pay.client.response.PayOrderResponse;
import xyz.xtt.pay.client.response.TblPayOrderDto;
import xyz.xtt.pay.entity.TblPayOrder;
import xyz.xtt.pay.entity.TblPayOrderLog;
import xyz.xtt.pay.mapper.TblPayOrderMapper;
import xyz.xtt.pay.service.ITblPayOrderLogService;
import xyz.xtt.pay.service.ITblPayOrderService;

/**
 * @author dale
 * @date 2025/1/15
 **/
@Service
public class TblPayOrderServiceImpl extends ServiceImpl<TblPayOrderMapper, TblPayOrder> implements ITblPayOrderService {
	@Autowired
	private ITblPayOrderLogService iTblPayOrderLogService;

	/**
	 * 根据业务类型和业务关联id获取支付订单
	 *
	 * @param payOrderBusinessTypeEnum
	 * @param businessRefId
	 * @return
	 */
	@Override
	public TblPayOrder getByBusiness(PayOrderBusinessTypeEnum payOrderBusinessTypeEnum, String businessRefId) {
		QueryWrapper<TblPayOrder> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("business_type", payOrderBusinessTypeEnum.getCode());
		queryWrapper.eq("business_ref_id", businessRefId);
		return getOne(queryWrapper);
	}

	/**
	 * 更新支付订单状态
	 *
	 * @param payOrderId 支付单id
	 * @param oldStatus  支付单当前状态
	 * @param newStatus  支付单新状态
	 * @return
	 */
	@Override
	public boolean updatePayStatus(Long payOrderId, PayOrderStatusEnum oldStatus, PayOrderStatusEnum newStatus) {
		long updateTime = System.currentTimeMillis();
		UpdateWrapper<TblPayOrder> updateWrapper = new UpdateWrapper<>();
		updateWrapper.eq("pay_order_id", payOrderId);
		updateWrapper.eq("pay_status", oldStatus.getCode());
		updateWrapper.set("pay_status", newStatus.getCode());
		updateWrapper.set("update_time", updateTime);
		if (Objects.equals(newStatus, PayOrderStatusEnum.PAY_SUCCESS)) {
			updateWrapper.set("pay_success_time", updateTime);
		}
		return update(updateWrapper);
	}

	/**
	 * 批量查询待支付订单
	 *
	 * @param fetchRequest 请求数量
	 * @return 待支付订单集合
	 */
	@Override
	public List<TblPayOrderDto> fetchUnPaidOrders(@Valid FetchUnPaidOrdersRequest fetchRequest) {
		QueryWrapper<TblPayOrder> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("pay_status", PayOrderStatusEnum.UN_PAY.getCode());
		IPage<TblPayOrder> page = page(new Page<>(fetchRequest.getPageNo(), fetchRequest.getPageSize()), queryWrapper);
		List<TblPayOrder> list = page.getRecords();
		return CollectionUtils.isEmpty(list) ? Collections.emptyList() : list.stream().map(this::convertToDto).collect(Collectors.toList());
	}

	/**
	 * 查询订单
	 *
	 * @param payOrderId
	 * @param appUserId
	 * @return
	 */
	@Override
	public TblPayOrder getPayOrder(Long payOrderId, Long appUserId) {
		QueryWrapper<TblPayOrder> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("pay_order_id", payOrderId);
		queryWrapper.eq("app_user_id", appUserId);
		return getOne(queryWrapper);
	}

	/**
	 * 更新支付成功
	 *
	 * @param payOrderId
	 * @return
	 */
	@Override
	public boolean updatePaySuccess(Long payOrderId) {
		return this.updatePaySuccess(payOrderId, null, null, null);
	}

	private TblPayOrderDto convertToDto(TblPayOrder payOrder) {
		TblPayOrderDto dto = new TblPayOrderDto();
		BeanUtils.copyProperties(payOrder, dto);
		return dto;
	}

	@Override
	public boolean mintAfterUpdateResult(Long id, Long transactionOrderId) {
		LambdaUpdateChainWrapper<TblPayOrder> update = new LambdaUpdateChainWrapper<>(baseMapper);
		return update
				.eq(TblPayOrder::getPayOrderId, id)
				.set(TblPayOrder::getBusinessRefId, transactionOrderId)
				.eq(TblPayOrder::getPayStatus, PayOrderStatusEnum.PAY_SUCCESS.getCode())
				.update();
	}

	/**
	 * 查询支付订单
	 *
	 * @param payOrderId
	 * @return
	 */
	@Override
	public TblPayOrderDto fetchPayOrder(Long payOrderId) {
		TblPayOrder payOrder = getById(payOrderId);
		return convertToDto(payOrder);
	}

	/**
	 * 更新支付订单业务附加信息
	 *
	 * @param payOrderId
	 * @param jsonStr
	 */
	@Override
	public void updatePayOrderBusinessAttach(long payOrderId, String jsonStr) {
		UpdateWrapper<TblPayOrder> updateWrapper = new UpdateWrapper<>();
		updateWrapper.eq("pay_order_id", payOrderId);
		updateWrapper.set("business_attach", jsonStr);
		updateWrapper.set("update_time", System.currentTimeMillis());
		update(updateWrapper);
	}

	/**
	 * 根据业务订单id查询支付订单
	 *
	 * @param businessOrderId
	 * @return
	 */
	@Override
	public TblPayOrder getPayOrderByBusinessOrder(Long businessOrderId) {
		LambdaQueryChainWrapper<TblPayOrder> query = new LambdaQueryChainWrapper<>(baseMapper);
		return query.eq(TblPayOrder::getBusinessOrderId, businessOrderId).one();
	}

	@Override
	public TblPayOrder getByIdForUpdate(Long payOrderId) {
		LambdaQueryChainWrapper<TblPayOrder> query = new LambdaQueryChainWrapper<>(baseMapper);
		return query.eq(TblPayOrder::getPayOrderId, payOrderId).last("for update").one();
	}

	@Override
	public TblPayOrder getByBusinessOrderIdForUpdate(Long businessOrderId) {
		LambdaQueryChainWrapper<TblPayOrder> query = new LambdaQueryChainWrapper<>(baseMapper);
		return query.eq(TblPayOrder::getBusinessOrderId, businessOrderId).last("for update").one();
	}

	@Override
	public boolean updatePayCancel(Long payOrderId, String reasonRemark) {
		long now = System.currentTimeMillis();
		TblPayOrderLog payOrderLog = TblPayOrderLog
				.builder()
				.payOrderId(payOrderId)
				.payOrderLogId(IdUtil.getSnowflakeNextId())
				.payStatus(PayOrderStatusEnum.PAY_CANCEL.getCode())
				.detail(reasonRemark)
				.createTime(now)
				.build();
		boolean result = iTblPayOrderLogService.save(payOrderLog);
		if (!result) {
			return false;
		}
		UpdateWrapper<TblPayOrder> updateWrapper = new UpdateWrapper<>();
		updateWrapper.eq("pay_order_id", payOrderId);
		updateWrapper.in("pay_status", Arrays.asList(PayOrderStatusEnum.UN_PAY.getCode(), PayOrderStatusEnum.PAYING.getCode()));
		updateWrapper.set("pay_status", PayOrderStatusEnum.PAY_CANCEL.getCode());
		updateWrapper.set("update_time", now);
		return update(updateWrapper);
	}

	@Override
	public TblPayOrder getPayOrderByBusinessOrder4Update(Long businessOrderId) {
		LambdaQueryChainWrapper<TblPayOrder> query = new LambdaQueryChainWrapper<>(baseMapper);
		return query.eq(TblPayOrder::getBusinessOrderId, businessOrderId).last("for update").one();
	}

	@Override
	public boolean updatePaySuccess(Long payOrderId, String thirdTradeNo, Integer payMode, Integer payModeSub) {
		long now = System.currentTimeMillis();
		TblPayOrderLog payOrderLog = TblPayOrderLog
				.builder()
				.payOrderId(payOrderId)
				.payOrderLogId(IdUtil.getSnowflakeNextId())
				.payStatus(PayOrderStatusEnum.PAY_SUCCESS.getCode())
				.createTime(now)
				.build();
		boolean result = iTblPayOrderLogService.save(payOrderLog);
		if (!result) {
			return false;
		}

		UpdateWrapper<TblPayOrder> updateWrapper = new UpdateWrapper<>();
		updateWrapper.eq("pay_order_id", payOrderId);
		updateWrapper.in("pay_status", Arrays.asList(PayOrderStatusEnum.UN_PAY.getCode(), PayOrderStatusEnum.PAYING.getCode()));
		updateWrapper.set("pay_status", PayOrderStatusEnum.PAY_SUCCESS.getCode());
		updateWrapper.set("update_time", now);
		updateWrapper.set("pay_success_time", now);
		if (StringUtils.isNotBlank(thirdTradeNo)) {
			updateWrapper.set("pay_trade_no", thirdTradeNo);
		}
		if (payMode != null) {
			updateWrapper.set("pay_mode", payMode);
		}
		if (payModeSub != null) {
			updateWrapper.set("pay_mode_sub", payModeSub);
		}
		return update(updateWrapper);
	}

	/**
	 * 根据审核ID 查询支付状态
	 *
	 * @param auditId
	 * @return
	 */
	@Override
	public PayOrderResponse infoPayOrderWithBusinessRefId(String businessRefId, PayOrderBusinessTypeEnum businessType) {
		MPJLambdaWrapper<TblPayOrder> query = JoinWrappers
				.lambda(TblPayOrder.class)
				.eq(TblPayOrder::getBusinessRefId, businessRefId)
				.eq(TblPayOrder::getBusinessType, businessType.getCode());
		PayOrderResponse one = query.one(PayOrderResponse.class);
		return one;
	}
}
